package com.jy.modules.cims.common.open.api;

import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.jy.modules.cims.common.open.api.crypt.CryptHelper;
import com.jy.modules.cims.common.open.api.dto.EntryParameter;
import com.jy.modules.cims.common.open.api.dto.HttpParam;
import com.jy.modules.cims.common.open.api.dto.ResponseContent;
import com.jy.modules.cims.common.open.api.dto.ResponseData;
import com.jy.modules.cims.common.open.api.enums.EntryResponseEnum;
import com.jy.modules.cims.common.open.api.exception.JieYueApiException;
import com.jy.modules.cims.common.open.api.log.InfoLogger;
import com.jy.modules.cims.common.open.api.log.JieYueLogger;
import com.jy.modules.cims.common.open.api.util.HttpClientUtils;
import com.jy.modules.cims.common.open.api.util.JieYueApiUtils;

public class JieYueApiHelper {
	private JieYueLogger log;
	private String md5Key;
	private String aesKey;
	private Charset charset = Charset.forName("UTF-8");
	private HttpParam httpParam;
	private String appId;
	private String version = "1.0";

	public JieYueApiHelper(JieYueLogger log, String md5Key, String aesKey, String charset, HttpParam httpParam, String appId, String version) {
		this.log = log;
		this.md5Key = md5Key;
		this.aesKey = aesKey;
		if (charset != null) {
			this.charset = Charset.forName(charset);
		}
		if (httpParam == null) {
			this.httpParam = new HttpParam();
		} else {
			this.httpParam = httpParam;
		}
		this.appId = appId;
		if (version != null) {
			this.version = version;
		}
	}

	public JieYueApiHelper(String md5Key, String aesKey, String appId) {
		this(new InfoLogger(JieYueApiHelper.class), md5Key, aesKey, null, null, appId, null);
	}

	public String postForm(String url, Map<String, String> params) {
		return postForm(url, params, this.httpParam);
	}

	public String postForm(String url, Map<String, String> params, HttpParam httpParam) {
		if (httpParam == null) {
			httpParam = new HttpParam();
		}
		String result = null;
		try {
			result = HttpClientUtils.postForm(url, params, httpParam.getHeaders(), httpParam.getCharset(), httpParam.getConnTimeout(),
					httpParam.getReadTimeout());
		} catch (Exception e) {
			this.log.error("发送请求失败", e);
			throw new JieYueApiException(e);
		}
		return result;
	}

	public String aesEncrypt(String msg) {
		return CryptHelper.aesEncrypt(this.charset, msg, this.aesKey);
	}

	public String aesDecrypt(String msg) {
		return CryptHelper.aesDecrypt(this.charset, msg, this.aesKey);
	}

	public String md5(Map<String, String> param) {
		return CryptHelper.md5(this.charset, param, this.md5Key);
	}

	public String md5(Object obj, String... exclude) {
		return CryptHelper.md5(this.charset, obj, this.md5Key, exclude);
	}

	public void assembelRequest(EntryParameter request, Object param) {
		if (param != null) {
			String res = JieYueApiUtils.toString(param);
			this.log.print("将请求主体数据param转化为json：" + res);
			String resAes = aesEncrypt(res);
			this.log.print("将数据aes加密后的数据：" + res);
			request.setContent(resAes);
		} else {
			this.log.print("请求参数为空，不对请求参数处理");
		}
		String sign = md5(request, new String[] { "sign" });
		this.log.print("生成签名sign：" + sign);
		request.setSign(sign);
	}

	public ResponseContent sendRequest(String url, String method, Object param) {
		return sendRequest(url, method, param, this.httpParam);
	}

	public ResponseContent sendRequest(String url, String method, Object param, HttpParam httpParam) {
		ResponseContent res = null;
		EntryParameter request = initParam(method);

		assembelRequest(request, param);
		Map<String, String> params = JieYueApiUtils.obj2Map(request, new String[0]);
		this.log.print("发送请求（" + url + "）：" + params);
		String response = postForm(url, params, httpParam);
		this.log.print("收到响应：" + response);
		res = (ResponseContent) JieYueApiUtils.parse(response, ResponseContent.class);

		return res;
	}

	public <T> ResponseData<T> sendRequestRaw(String url, String method, Object param, HttpParam httpParam, Class<T> c) {
		ResponseData<T> res = null;
		ResponseContent rc = sendRequest(url, method, param, httpParam);
		res = ResponseData.fromResponseContent(rc, c);
		if (res.successVisit()) {
			res.setSign(singCheck(rc.getSign(), rc, new String[] { "sign" }));
		}
		if (res.getOriginalData() != null) {
			this.log.print("加密返回信息：" + res.getOriginalData());
			res.setOriginalData(aesDecrypt(res.getOriginalData()));
			this.log.print("解密后的返回信息：" + res.getOriginalData());
		}
		return res;
	}

	public boolean singCheck(String sign, Object param, String... exclude) {
		boolean result;
		if (sign == null) {
			result = false;
		} else {
			String signTemp = md5(param, new String[] { "sign" });
			this.log.print("传入签名：" + sign + ", 生成签名：" + signTemp);
			result = sign.equals(signTemp);
		}
		return result;
	}

	public <T> ResponseData<T> sendRequest(String url, String method, Object param, Class<T> c) {
		return sendRequest(url, method, param, c, this.httpParam);
	}

	public <T> ResponseData<T> sendRequestForList(String url, String method, Object param, Class<T> c) {
		return sendRequestForList(url, method, param, c, this.httpParam);
	}

	public <T> ResponseData<T> sendRequest(String url, String method, Object param, Class<T> c, HttpParam httpParam) {
		ResponseData<T> res = null;

		res = sendRequestRaw(url, method, param, httpParam, c);
		if (res.getOriginalData() != null) {
			res.setData(JieYueApiUtils.parse(res.getOriginalData(), c));
		}
		return res;
	}

	private EntryParameter initParam(String method) {
		EntryParameter param = new EntryParameter();

		param.setAppId(this.appId);
		param.setVersion(this.version);
		param.setMethod(method);

		param.setTimestamp(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

		return param;
	}

	public <T> ResponseData<T> sendRequestForList(String url, String method, Object param, Class<T> c, HttpParam httpParam) {
		ResponseData<T> res = null;

		res = sendRequestRaw(url, method, param, httpParam, c);
		if (res.getOriginalData() != null) {
			res.setDataList(JieYueApiUtils.parseList(res.getOriginalData(), c));
		}
		return res;
	}

	public boolean checkSign(EntryParameter param) {
		return singCheck(param.getSign(), param, new String[] { "sign" });
	}

	public <T> T parseData(EntryParameter param, Class<T> c) {
		String data = param.getContent();
		T result = null;
		if (data != null) {
			this.log.print("需要解密数据：" + data);
			String msg = aesDecrypt(data);
			this.log.print("解密后的数据：" + msg);
			result = JieYueApiUtils.parse(msg, c);
		}
		return result;
	}

	public <T> List<T> parseList(EntryParameter param, Class<T> c) {
		String data = param.getContent();
		List<T> result = null;
		if (data != null) {
			this.log.print("需要解密数据：" + data);
			String msg = aesDecrypt(data);
			this.log.print("解密后的数据：" + msg);
			result = JieYueApiUtils.parseList(msg, c);
		}
		return result;
	}

	public void assembleResponse(ResponseContent response, Object data) {
		if (EntryResponseEnum.isSuccess(response.getRetCode())) {
			String msg = JieYueApiUtils.toString(data);
			this.log.print("数据对象转化为字符串：" + msg);
			String enMsg = aesEncrypt(msg);
			this.log.print("数据加密：" + enMsg);
			response.setData(enMsg);
			String sign = md5(response, new String[] { "sign" });
			this.log.print("签名：" + sign);
			response.setSign(sign);
		} else {
			this.log.print("没有成功访问接口，不生成签名，不对参数进行处理");
		}
	}
}
